package com.sh.data.engine.domain.common.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.sh.data.engine.common.exception.BusinessException;
import com.sh.data.engine.common.util.ServletUtils;
import com.sh.data.engine.domain.base.model.enums.DirectoryMenuEnum;
import com.sh.data.engine.domain.common.model.domain.DirectoryDomain;
import com.sh.data.engine.domain.common.model.mapper.DirectoryDomainMapper;
import com.sh.data.engine.domain.common.model.param.UpsertDirectoryParam;
import com.sh.data.engine.domain.common.service.DirectoryService;
import com.sh.data.engine.repository.dao.common.DirectoryMapper;
import com.sh.data.engine.repository.dao.common.entity.DirectoryEntity;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author：jingchen.hr
 * @descripion:
 * @data:5/5/202210:32 AM
 */
@Service
public class DirectoryServiceImpl extends ServiceImpl<DirectoryMapper, DirectoryEntity>
    implements DirectoryService {

    @Autowired
    private DirectoryMapper directoryMapper;

    @Autowired
    private DirectoryDomainMapper directoryDomainMapper;

    @Override
    public List<DirectoryDomain> getDirListWithOutTopLevel(
        Long projectId, DirectoryMenuEnum directoryMenuEnum, String search) {

        LambdaQueryWrapper<DirectoryEntity> query = new QueryWrapper<DirectoryEntity>().lambda();
        query
            .eq(DirectoryEntity::getProjectId, projectId)
            .eq(DirectoryEntity::getMenuCode, directoryMenuEnum.getCode())
            .orderByDesc(DirectoryEntity::getCreateTime)
            .like(StringUtils.isNotBlank(search), DirectoryEntity::getDirName, search);

        List<DirectoryEntity> multi = directoryMapper.selectList(query);
        List<DirectoryDomain> directoryDomains = directoryDomainMapper.map(multi);
        // 如果multi是个空List，经过ConvertUtil返回个抽象的空List，导致下面向里面塞值的时候报错，所有要转换下
        if (CollectionUtils.isEmpty(directoryDomains)) {
            directoryDomains = Lists.newArrayList();
            return directoryDomains;
        }
        return directoryDomains;
    }

    @Override
    public List<DirectoryDomain> getDirList(
        Long projectId, DirectoryMenuEnum directoryMenuEnum, String search) {

        LambdaQueryWrapper<DirectoryEntity> query = new QueryWrapper<DirectoryEntity>().lambda();
        query
            .eq(DirectoryEntity::getProjectId, projectId)
            .eq(DirectoryEntity::getMenuCode, directoryMenuEnum.getCode())
            .orderByDesc(DirectoryEntity::getCreateTime)
            .like(StringUtils.isNotBlank(search), DirectoryEntity::getDirName, search);

        List<DirectoryEntity> multi = directoryMapper.selectList(query);
        List<DirectoryDomain> directoryDomains = directoryDomainMapper.map(multi);
        // 如果multi是个空List，经过ConvertUtil返回个抽象的空List，导致下面向里面塞值的时候报错，所有要转换下
        if (CollectionUtils.isEmpty(directoryDomains)) {
            directoryDomains = Lists.newArrayList();
        }
        // 手动塞顶级目录，避免未定义目录的任务无法展示
        DirectoryDomain directoryDomain = new DirectoryDomain();
        directoryDomain.setId(Long.valueOf(DirectoryMenuEnum.PARENT_DIR.getCode()));
        directoryDomain.setPid(null);
        directoryDomain.setDirName(DirectoryMenuEnum.PARENT_DIR.getRemark());
        directoryDomains.add(directoryDomain);
        return directoryDomains;
    }

    @Override
    public Boolean upsetDir(UpsertDirectoryParam param) {
        Long id = param.getId();
        Long pid = Objects.isNull(param.getPid()) ? 0L : param.getPid();
        if (Objects.nonNull(id)) {
            if (id.equals(pid)) {
                throw new BusinessException("父级目录不能选择当前目录");
            }
            List<DirectoryEntity> childrenById =
                getChildrenById(
                    id, param.getProjectId(), DirectoryMenuEnum.valueOfCode(param.getMenuCode()));
            List<Long> childrenIds =
                childrenById.stream().map(DirectoryEntity::getId).collect(Collectors.toList());
            if (childrenIds.contains(pid)) {
                throw new BusinessException("父级目录不能移动到子级目录");
            }
            DirectoryEntity update = new DirectoryEntity();
            update.setDirName(param.getDirName());
            update.setId(id);
            update.setPid(pid);
            update.setUpdateTime(new Date());
            directoryMapper.updateById(update);
            return Boolean.TRUE;
        }
        DirectoryEntity insert = new DirectoryEntity();
        insert.setDirName(param.getDirName());
        insert.setMenuCode(param.getMenuCode());
        insert.setPid(pid);
        insert.setProjectId(param.getProjectId());
        insert.setMenuCode(param.getMenuCode());
        LambdaQueryWrapper<DirectoryEntity> query = new QueryWrapper<DirectoryEntity>().lambda();
        query
            .eq(DirectoryEntity::getDirName, param.getDirName())
            .eq(DirectoryEntity::getMenuCode, param.getMenuCode())
            .eq(DirectoryEntity::getPid, pid)
            .eq(DirectoryEntity::getProjectId, param.getProjectId())
            .eq(DirectoryEntity::getMenuCode, param.getMenuCode());
        DirectoryEntity oneTkSelectStyle = directoryMapper.selectOne(query);
        if (Objects.nonNull(oneTkSelectStyle)) {
            throw new BusinessException("存在相关名称的目录");
        }
        directoryMapper.insert(insert);
        return Boolean.TRUE;
    }

    @Override
    public Boolean deleteDir(Long id, DirectoryMenuEnum directoryMenuEnum) {
        Long projectId = ServletUtils.getProjectId();
        List<DirectoryEntity> childrenById =
            getChildrenById(id, projectId, directoryMenuEnum);
        // id下的子级，不包含id本身
        List<Long> ids = childrenById.stream().map(DirectoryEntity::getId).collect(Collectors.toList());
        ids.add(id);
        directoryMapper.removeByIds(ids);
        return Boolean.TRUE;
    }

    @Override
    public List<DirectoryEntity> getChildrenById(
        Long id, Long projectId, DirectoryMenuEnum directoryMenuEnum) {
        Queue<Long> queue = new LinkedList<>();
        queue.add(id);
        ArrayList<DirectoryEntity> children = Lists.newArrayList();
        while (queue.size() > 0) {
            Long poll = queue.poll();
            LambdaQueryWrapper<DirectoryEntity> query = new QueryWrapper<DirectoryEntity>().lambda();
            query
                .eq(DirectoryEntity::getPid, poll)
                .eq(DirectoryEntity::getProjectId, projectId)
                .eq(DirectoryEntity::getMenuCode, directoryMenuEnum.getCode());
            List<DirectoryEntity> multi = directoryMapper.selectList(query);
            if (CollectionUtils.isNotEmpty(multi)) {
                children.addAll(multi);
                List<Long> ids = multi.stream().map(DirectoryEntity::getId).collect(Collectors.toList());
                queue.addAll(ids);
            }
        }
        return children;
    }

    @Override
    public DirectoryEntity insetDirectory(UpsertDirectoryParam param) {

        DirectoryEntity insert = new DirectoryEntity();
        insert.setDirName(param.getDirName());
        insert.setMenuCode(param.getMenuCode());
        insert.setPid(param.getPid());
        insert.setProjectId(param.getProjectId());
        insert.setMenuCode(param.getMenuCode());
        LambdaQueryWrapper<DirectoryEntity> query = new QueryWrapper<DirectoryEntity>().lambda();
        query
            .eq(DirectoryEntity::getDirName, param.getDirName())
            .eq(DirectoryEntity::getMenuCode, param.getMenuCode())
            .eq(DirectoryEntity::getPid, param.getPid())
            .eq(DirectoryEntity::getProjectId, param.getProjectId());
        DirectoryEntity oneTkSelectStyle = directoryMapper.selectOne(query);
        if (Objects.nonNull(oneTkSelectStyle)) {
            throw new BusinessException("存在相关名称的目录");
        }
        directoryMapper.insert(insert);
        return insert;
    }

    @Override
    public DirectoryEntity getDirectoryEntityById(Long id) {

        if (Long.valueOf(DirectoryMenuEnum.PARENT_DIR.getCode()).equals(id)) {
            DirectoryEntity directoryEntity = new DirectoryEntity();
            directoryEntity.setDirName(DirectoryMenuEnum.PARENT_DIR.getRemark());
            return directoryEntity;
        }
        return directoryMapper.selectById(id);
    }
}
